/*
  Copyright (c) 2014 Dimitrij Gester

  "Smart RC TX" is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  "Smart RC TX" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with "Smart RC TX"; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package com.codeplex.smartrctx.configurator.communication;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;

public abstract class CommLink {

	public interface DataReceivedHandler {
		void dataReceived(String data);
	}

	protected class Cmm extends Thread {

		private static final int RECEIVE_ACCUMULATION_TIME = 1;

		@Override
		public void run() {
			byte[] buffer = new byte[255];
			StringBuilder stringBuilder = new StringBuilder();

			while (true) {
				try {
					Thread.sleep(RECEIVE_ACCUMULATION_TIME);
					int count = in.read(buffer);
					if (count > 0) {
						String data = new String(buffer, "ISO-8859-1");
						data = data.substring(0, count);

						int nl = data.indexOf("\n");
						while (nl >= 0) {
							String prefix = data.substring(0, nl);
							if (nl + 1 <= data.length())
								data = data.substring(nl + 1);
							else
								data = "";
							nl = data.indexOf("\n");

							stringBuilder.append(prefix);
							raiseDataReceivedEvent(stringBuilder.toString().trim());
							stringBuilder.delete(0, stringBuilder.length());
						}

						if (data.length() > 0)
							;
						stringBuilder.append(data);

					}
				} catch (IOException e) {
					return;
				} catch (InterruptedException e) {
					return;
				}
			}
		}
	}

	protected boolean connected;
	private ArrayList<DataReceivedHandler> dataReceiver = new ArrayList<DataReceivedHandler>();
	protected Thread handler;
	protected InputStream in;
	protected OutputStream out;

	public abstract void setCommTarget(String device) throws IOException;

	public final void disconnect() throws IOException {
		if (this.connected) {
			this.handler.interrupt();
			this.in.close();
			this.out.close();
			doDisconnect();
		}
		this.connected = false;
	}

	protected abstract void doDisconnect() throws IOException;

	public final void connect() throws IOException {
		if (!this.connected) {
			doConnect();

			this.handler = new Cmm();
			this.handler.start();
		}

		this.connected = true;
	};

	protected abstract void doConnect() throws IOException;

	public abstract boolean isEnabled();
	
	public final boolean isConnected() {
		return this.connected;
	}

	public CommLink() {
		super();
	}

	public void addOnReceiveHandler(DataReceivedHandler handler) {
		if(handler == null) {
			throw new NullPointerException();
		}
		
		if(!this.dataReceiver.contains(handler)) {
			this.dataReceiver.add(handler);
		}
	}

	protected void raiseDataReceivedEvent(String data) {
		for(DataReceivedHandler r : this.dataReceiver) {
			r.dataReceived(data);
		}
	}

	protected void setOutputStream(OutputStream os) throws IOException {
		this.out = os;
	}

	protected void setInputStream(InputStream is) throws IOException {
		this.in = is;
	}

	public void send(String data) throws IOException {
		if (!connected)
			return;
		this.out.write(data.getBytes());
	}

	public void send(byte[] data) throws IOException {
		if (!connected)
			return;
		this.out.write(data);
	}

	public void send(byte data) throws IOException {
		if (!connected)
			return;
		this.out.write(data);
	}

}